home *** CD-ROM | disk | FTP | other *** search
/ Shareware Grab Bag / Shareware Grab Bag.iso / 090 / yase.arc / FILEPRIM.ASM < prev    next >
Assembly Source File  |  1986-12-13  |  10KB  |  285 lines

  1. ******************************************************************
  2. * COPYRIGHT (C) 1986 by Donald Krantz and James Stanley
  3. * - Note: This is a real, live, actual, registered copyright,
  4. *   and should be treated as such. This source code is from
  5. *   the book "68000 Assembly Language", Krantz and Stanley,
  6. *   Addison-Wesley Publishing Company, Reading, MA, 1986.
  7. *   Permission granted by the authors for non-commercial use
  8. *   in programs released to the public domain, as long as this
  9. *   copyright notice remains attached and visible.
  10. *
  11. ***************************************************************
  12. * File Primitive Operations - CP/M-68K
  13. *
  14. * All routines interface to CP/M-68K files. FCB and FILE block
  15. * definitions are contained in FCB.H.
  16.  
  17. #fcb.h
  18.     .xdef    open,close,fgetc,fputc
  19.  
  20. * Routines:    OPEN    Opens a file for input or output.
  21. *         Entry: P0.L points to FILE block. P1.L points to
  22. *                null-terminated name string. P2.W = 0
  23. *            for "File must Exist", nonzero
  24. *            for "Create new and erase old".
  25. *         Exit:  File opened or D0.W = -1
  26. *
  27. *        CLOSE    Closes a file. Flushes current buffer
  28. *            if dirty. 
  29. *         Entry:    P0.L points to FILE block.
  30. *         Exit:    File closed or D0.W = -1
  31. *
  32. *        FGETC    Returns next char from file.
  33. *         Entry: P0.L points to FILE block.
  34. *         Exit:    D0.W = char or -1 on error.
  35. *
  36. *        FPUTC    Writes next char to file.
  37. *         Entry:    P0.L points to FILE block.
  38. *            P1.W is the char to write.
  39. *         Exit:    D0.W = 0 for success, -1 on failure.
  40. *
  41. *****************************************************************
  42. open:
  43.     link    a6,#0        * Set stack frame
  44.     movem.l    d1/d2/a0/a1/a2,-(a7)
  45.     bsr    parse_name    * Parses filename to FCB
  46.     tst.w    d0        * Check return from PARSE_NAME
  47.     bmi    exit_open    * Exit on error
  48.     bsr    fillfcb        * Set balance of FCB
  49.     move.l    8(a6),d1    * Get FCB addr for CP/M calls
  50.     tst.w    16(a6)        * Open new file or old?
  51.     bne    make_new    * Make new file, erase any old.    
  52. must_exist:    
  53.     move.w    #$000f,d0    * CP/M OPEN FILE Function Code
  54.     trap    #2        * Call CP/M - Open existing file
  55.     bra    exit_open    * Exit
  56. make_new:
  57.     move.w    #$0013,d0    * CP/M DELETE FILE Function code
  58.     trap    #2        * Call CP/M - delete any old file
  59.     move.w    #$0016,d0    * CP/M MAKE FILE Function code
  60.     trap    #2        * Call CP/M - attempt create
  61. exit_open:
  62.     ext.w    d0        * Convert CP/M return to our type
  63.     movem.l    (a7)+,d1/d2/a0/a1/a2
  64.     unlk    a6        * Restore caller's stack frame
  65.     rts
  66. *
  67. *****************************************************************
  68. * PARSE_NAME parses a C name string into CP/M-68K FCB. Uses
  69. * caller's stack frame. Consider this a local procedure to OPEN.
  70. parse_name:
  71.     move.l    8(a6),a0    * Pick up FCB address
  72.     move.l    12(a6),a1    * Pick up name string
  73.     move.w    #10,d0        * Loop counter for blank filling
  74. blank_loop:
  75.     move.b    #' ',1(a0,d0.w)    * Blank fill name "backwards"
  76.     dbra    d0,blank_loop    * Continue for 11 bytes
  77. *
  78.     cmp.b    #':',1(a1)    * Check for drivespec
  79.     bne    no_drive    * No drivespec, jump over
  80.     move.b    (a1),(a0)    * Transfer drivespec
  81.     and.b    #$0f,(a0)+    * Make into 0..16 drivecode
  82.     addq.l    #2,a1        * Put pointer past drivespec
  83.     bra    name_xfr    * Go transfer name
  84. no_drive:
  85.     clr.b    (a0)+        * Set default drivecode    
  86. name_xfr:
  87.     move.w    #7,d0        * Start with filename part
  88. name_loop:
  89.     move.b    (a1)+,d2    * Pickup name character
  90.     beq    parse_chk    * Found a terminal null...
  91.     cmp.b    #'.',d2        * Look for delimiter
  92.     beq    ext_xfr        * Parse extension
  93.     bsr    check        * Make uppercase & screen chars
  94.     tst.b    d1        * D1 = -1 for illegal character
  95.     bmi    parse_err    * Exit if CHECK found error
  96.     move.b    d2,(a0)+    * Put char in FCB
  97.     dbra    d0,name_loop    * Try again
  98. * If we're here, 8 filename chars were found. Skip period.
  99.     move.b    (a1)+,d2    * Move pointer and check char
  100.     cmp.b    #'.',d2        * Double check for period
  101.     beq    ext_xfr        * OK, let's continue  
  102.     bra    parse_err    * Badly formed name string.
  103. ext_xfr:
  104.     move.l    8(a6),a0    * Re-sync FCB pointer
  105.     adda    #type,a0    * Point at TYPE field
  106.     move.w    #2,d0        * Three chars only for filetype
  107. ext_loop:
  108.     move.b    (a1)+,d2    * Pickup filetype char
  109.     beq    parse_chk    * Found terminal null...
  110.     bsr    check        * Make uppercase and screen chars
  111.     tst.b    d1        * Look for error return
  112.     bmi    parse_err    * Exit if CHECK found error.
  113.     move.b    d2,(a0)+    * Put filetype char into FCB
  114.     dbra    d0,ext_loop    * Go for next
  115. * If we're here, 3 filetype chars were found. Check for null.
  116.     tst.b    (a1)        * Is it null?
  117.     bne    parse_err    * No, return error
  118. parse_chk:
  119.     move.l    8(a6),a0    * Get FCB base addr again
  120.     cmp.b    #' ',name(a0)    * At least one name char?
  121.     beq    parse_err    * Nope, return error.
  122.     clr.w    d0        * "Good" return code
  123.     rts
  124. parse_err:
  125.     move.w    #-1,d0        * "Bad" return code
  126.     rts
  127. *
  128. *****************************************************************
  129. * FILLFCB zeros the non-name portion of the FCB. Local to OPEN.
  130. fillfcb:
  131.     move.l    8(a6),a0    * Load FCB base address
  132.     adda    #extent,a0    * Index past name portion
  133.     move.w    #dma_buf-extent-1,d0    * Loop count
  134. fill_loop:
  135.     clr.b    (a0)+        * Load zeros in all FILE fields
  136.     dbra    d0,fill_loop    * Continue for all bytes in FILE
  137.     tst.w    16(a6)        * Is this a write?
  138.     bne    fill_exit    * Yes, CURCHR is ok as zero.
  139.     move.l    8(a6),a0    * Get FCB address again.
  140.     move.w    #128,curchr(a0)    * Mark as "Need to read"
  141. fill_exit:
  142.     rts
  143. *
  144. *****************************************************************
  145. * CHECK converts lowercase to uppercase and screens chars CP/M
  146. * considers illegal name characters.
  147. check:
  148.     cmp.b    #'a',d2        * Check for lowercase first.
  149.     blt    not_lower    * It's less than 'a'
  150.     cmp.b    #'z',d2        * Less than 'z'?
  151.     bgt    not_lower    * It's greater than 'z'
  152.     and.b    #$5f,d2        * Makes D2.B uppercase
  153. not_lower:
  154.     move.w    #18,d1        * 19 illegal name chars
  155.     lea    bad_chars,a2    * Get name array base
  156. chk_loop:
  157.     cmp.b    (a2)+,d2    * Test for bad char
  158.     beq    chk_err        * Bad char, return error
  159.     dbra    d1,chk_loop    * Keep trying.
  160.     clr.w    d1        * "Good" error return
  161.     rts            * "Good" exit
  162. chk_err:
  163.     move.w    #-1,d1        * "Bad" error return
  164.     rts            * "Bad" exit
  165. bad_chars:
  166.     dc.b    '.:[]()<>=*&,!|?/;+-'
  167.     even            * Force alignment
  168. *
  169. *****************************************************************
  170. * CLOSE    Closes a file. Flushes current buffer if dirty. 
  171. close:
  172.     link    a6,#0        * Setup stack frame
  173.     movem.l    d1/a0/a1,-(a7)    * Save caller's registers
  174.     move.l    8(a6),a0    * Pick up FCB base address
  175.     bsr    put_eof        * Add ASCII EOF (^Z)
  176.     bmi    exit_close    * Branch if write failed
  177.     move.l    d1,a0        * Setup CP/M parameter
  178.     move.w    #$0010,d0    * CP/M CLOSE FILE function code
  179.     trap    #2        * Close the file
  180. exit_close:
  181.     ext.w    d0        * Convert CP/M return to our type
  182.     movem.l    (a7)+,d1/a0/a1     * Restore caller's registers
  183.     unlk    a6        * Restore caller's stack frame
  184.     rts
  185. *
  186. *****************************************************************
  187. * PUT_EOF fills the end of the current DMA buffer with ^Z
  188. put_eof:
  189.     cmp.w    #128,curchr(a0) * Check if we need to add another
  190.     bne    do_rest        * record with EOFs. (jump on NO)
  191.     tst.w    dirty(a0)    * look for empty record
  192.     beq    do_rest        * jump if this record empty
  193.     bsr    write_buf    * Flush current record
  194. do_rest:
  195.     move.w    #127,d0        * Set up number of chars to fill
  196.     sub.w    curchr(a0),d0    * less current character count
  197.     adda    curchr(a0),a0    * Get address of first fill char
  198.     adda    #dma_buf,a0    * Need this too.
  199. put_loop:
  200.     move.b    #$1a,(a0)+    * Insert character
  201.     dbra    d0,put_loop    * Continue through buffer
  202.     bsr    write_buf    * Flush filled record
  203.     rts
  204. *
  205. *****************************************************************
  206. * FPUTC puts a character to a disk file.
  207. fputc:
  208.     link    a6,#0        * Freeze stack frame
  209.     movem.l    a0/d1,-(a7)    * Save caller's registers
  210.     move.l    8(a6),a0    * Grab FCB
  211.     cmp.w    #128,curchr(a0)    * Check for record full
  212.     bne    just_put    * Nope, we're OK.
  213.     bsr    write_buf    * Flush current record
  214. just_put:
  215.     move.w    curchr(a0),d0    * Get current char count
  216.     addq.w    #1,curchr(a0)    * Bump counter
  217.     move.w    #-1,dirty(a0)    * Make dirty
  218.     move.b    13(a6),dma_buf(a0,d0.w)    * Save character
  219.     movem.l    (a7)+,a0/d1    * Restore caller's registers
  220.     unlk    a6        * Restore caller's stack frame
  221.     rts
  222. *
  223. *****************************************************************
  224. * WRITE_BUF writes the current record to disk and resets FILE buf
  225. write_buf:
  226.     move.l    8(a6),d1    * Get FCB base address
  227.     add.l    #dma_buf,d1    * Compute DMA buffer address
  228.     move.w    #$001a,d0    * CP/M SET DMA ADDRESS Function
  229.     trap    #2        * Setup DMA address
  230.     move.l    8(a6),a0    * Get FCB base address 
  231.     clr.w    dirty(a0)    * Mark dirty flag as "clean"
  232.     clr.w    curchr(a0)    * Set current char pointer to 0
  233.     move.l    a0,d1        * Get FCB address for CP/M
  234.     move.w    #$0015,d0    * CP/M WRITE SEQUENTIAL Function
  235.     trap    #2        * Write record
  236.     ext.w    d0        * Convert CP/M return to our type
  237.     rts
  238. *
  239. *****************************************************************
  240. * FGETC returns the next character from a file.
  241. fgetc:
  242.     link    a6,#0        * Establish stack frame
  243.     movem.l    d1/a0,-(a7)    * Save caller's registers
  244.     move.l    8(a6),a0    * Get FCB address
  245.     cmp.w    #128,curchr(a0)    * Do we need to read a record?
  246.     blt    no_read        * No, just get character
  247.     bsr    get_rec        * Read a record
  248.     tst.w    d0        * Was there an error?
  249.     bmi    fget_err    * Yes, return error to caller
  250. no_read:
  251.     move.w    curchr(a0),d0    * Get current character counter
  252.     addq.w    #1,curchr(a0)    * Increment current char count
  253.     move.b    dma_buf(a0,d0.w),d0 * Load next character
  254.     cmp.b    #$1a,d0        * Is it EOF?
  255.     beq    fget_err    * Yes, return error.
  256.     ext.w    d0        * Make into type "int".
  257.     bra    fget_exit    * And return...
  258. fget_err:
  259.     move.w    #-1,d0        * Indicate error
  260. fget_exit:
  261.     movem.l    (a7)+,d1/a0    * Restore caller's registers
  262.     unlk    a6        * Restore caller's stack frame
  263.     rts
  264. *
  265. *****************************************************************
  266. * GET_REC - reads next record sequentially. Local to FGETx.
  267. get_rec:
  268.     move.l    a0,d1        * Get FCB base address for CP/M
  269.     add.l    #dma_buf,d1    * Compute DMA buffer address
  270.     move.w    #$001a,d0    * CP/M SET DMA ADDRESS Function
  271.     trap    #2        * Setup DMA address
  272.     move.l    a0,d1        * Get FCB base address for CP/M
  273.     move.w    #$0014,d0    * CP/M READ SEQUENTIAL function
  274.     trap    #2        * Get the record
  275.     clr.w    dirty(a0)    * Mark record as "Clean"
  276.     clr.w    curchr(a0)    * Reset character counter
  277.     tst.b    d0        * Look at return code
  278.     bne    grec_err    * Returned an error...
  279.     rts            * Return success
  280. grec_err:
  281.     move.w    #-1,d0        * Load error return
  282.     rts            * Return error
  283.     end
  284.